package com.jackrain.nea.oms.db;

import com.alibaba.fastjson.JSONObject;
import com.jackrain.nea.config.PropertiesConf;
import com.jackrain.nea.core.db.DataSourceContextHolder;
import com.jackrain.nea.core.db.DynamicDataSource;
import com.jackrain.nea.core.redis.CusRedisTemplate;
import com.jackrain.nea.exception.NDSException;
import com.jackrain.nea.oms.util.AES;
import com.jackrain.nea.oms.util.ObjectToUtil;
import com.jackrain.nea.util.ApplicationContextHandle;
import com.jackrain.nea.util.RedisOpsUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;
import org.springframework.boot.bind.RelaxedDataBinder;
import org.springframework.boot.bind.RelaxedPropertyResolver;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;

import javax.sql.DataSource;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

/**
 * Created by ZC on 2017/4/11.
 */
@Component
@Slf4j
public class DataSourceRunner {

    private Map<Object, Object> targetDataSources = new HashMap<>();

    private Map<String, DataSource> customDataources = new HashMap<>();

    private ConversionService conversionService = new DefaultConversionService();
    private PropertyValues dataSourcePropertyValues;
    // 如配置文件中未指定数据源类型，使用该默认值
    private static final Object DATASOURCE_TYPE_DEFAULT = "org.apache.tomcat.jdbc.pool.DataSource";
    private static final String aesin = "burgeonpassword131dfbwnh";

    private List<Map<String, Object>> mDsMaps = new LinkedList<>();

    @Autowired
    Environment env;

    public void initCustomDataSource(String tag) throws Exception {

        //查询RDIS
        CusRedisTemplate<String, String> redisTemplate = RedisOpsUtil.getStrRedisTemplate();
        String key = "ds_" + tag;
        String dsStr = ObjectToUtil.getString(redisTemplate.opsForHash().get(key, tag), "");
        if (ObjectToUtil.isNullOREmpty(dsStr)) {
            throw new NDSException("redis中" + tag + "数据源不存在！");
        }
        JSONObject dsObject = JSONObject.parseObject(dsStr);
        if (dsObject == null) {
            throw new NDSException("redis中" + tag + "数据源格式错误！");
        }
        int id = dsObject.getIntValue("id");
        long time = dsObject.getLongValue("modifieddate");
        if (id <= 0) {
            throw new NDSException("redis中" + tag + "数据源id错误！");
        }
        if (time <= 0) {
            throw new NDSException("redis中" + tag + "数据源modifieddate错误！");
        }

        //查找，判断是否需要更新
        int index = -1;
        for (int i = 0; i< mDsMaps.size();i++){
            Map<String, Object> map = mDsMaps.get(i);
            if (map == null){ continue;}
            if (tag.equals(map.get("tag"))){
                index = i;
                if (map.containsKey("id") && ObjectToUtil.getInt(map.get("id"), 0) == id
                        && map.containsKey("modifieddate") && ObjectToUtil.getLong(map.get("modifieddate"), 0) == time) {
                    log.debug("=================== datasource is exist");
                    return;
                }
            }
        }

        //解密
        String password = dsObject.getString("password");
        AES aes = new AES(aesin);
        password = aes.decrypt(password);
        dsObject.put("password", password);

        //设置数据源
        Map<String, Object> map = new HashMap();
        map.putAll(dsObject);
        addCustomDataources(tag, map);
        if (index < 0){
            mDsMaps.add(map);
        }else{
            mDsMaps.set(index,map);
        }

    }

    public void addCustomDataources(String tag, Map<String, Object> dsMap) {

//        log.debug("add dsMap========>" + dsMap.toString());

        log.debug("=================== add datasource");

        DynamicDataSource dynamicDataSource = ApplicationContextHandle.getBean(DynamicDataSource.class);
        //增加数据源
//        dsMap.put("driverClassName", "com.mysql.jdbc.Driver");
//        dsMap.put("url", "jdbc:mysql://rm-vy12az54hcq969h38.mysql.rds.aliyuncs.com:3306/sys_info?characterEncoding=UTF-8");
//        dsMap.put("username", "burgeon");
//        dsMap.put("password", "Burgeon123");
        DataSource ds = buildDataSource(dsMap);
        customDataources.put(tag, ds);
        dataBinder(ds, env);
        DataSourceContextHolder.dataSourceIds.add(tag);
        //设置动态切库类
        targetDataSources.putAll(customDataources);
        dynamicDataSource.setTargetDataSources(targetDataSources);
        dynamicDataSource.afterPropertiesSet();
    }

    /**
     * 动态构造数据源
     */
    public DataSource buildDataSource(Map<String, Object> dsMap) {
        try {
            Object type = dsMap.get("type");
            if (type == null) {
                type = DATASOURCE_TYPE_DEFAULT;// 默认DataSource
            }

            Class<? extends DataSource> dataSourceType;
            dataSourceType = (Class<? extends DataSource>) Class.forName((String) type);

            String driverClassName = dsMap.get("driverClassName").toString();
            String url = dsMap.get("url").toString();
            String username = dsMap.get("username").toString();
            String password = dsMap.get("password").toString();

            DataSourceBuilder factory = DataSourceBuilder.create().driverClassName(driverClassName).url(url)
                    .username(username).password(password).type(dataSourceType);
            return factory.build();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 为DataSource绑定属性
     */
    public void dataBinder(DataSource dataSource, Environment env) {
        RelaxedDataBinder dataBinder = new RelaxedDataBinder(dataSource);
        //dataBinder.setValidator(new LocalValidatorFactory().run(this.applicationContext));
        dataBinder.setConversionService(conversionService);
        dataBinder.setIgnoreNestedProperties(false);//false
        dataBinder.setIgnoreInvalidFields(false);//false
        dataBinder.setIgnoreUnknownFields(true);//true
        if (dataSourcePropertyValues == null) {
            Map<String, Object> rpr = new RelaxedPropertyResolver(env, "spring.datasource").getSubProperties(".");
            Map<String, Object> values = new HashMap<>(rpr);
            // 排除已经设置的属性
            values.remove("driverClassName");
            values.remove("url");
            values.remove("username");
            values.remove("password");
            dataSourcePropertyValues = new MutablePropertyValues(values);
        }
        dataBinder.bind(dataSourcePropertyValues);
    }


}
